

#include <cegfx/ceclipper.h>
#include <cegfx/cemacros.h>


ceClipper::ceClipper ()
{
}

void ceClipper::Clear ()
{
	planes.clear();
}


void ceClipper::AddPlane (const D3DXPLANE& plane)
{
	planes.push_back (plane);
}

void ceClipper::AddPlane (const D3DXVECTOR3& p, const D3DXVECTOR3& n)
{
	static D3DXPLANE plane;
	D3DXPlaneFromPointNormal(&plane, &p, &n);
	planes.push_back (plane);
}

void ceClipper::AddPlane (const D3DXVECTOR3& p0, const D3DXVECTOR3& p1, const D3DXVECTOR3& p2)
{
	static D3DXPLANE plane;
	D3DXPlaneFromPoints (&plane, &p0, &p1, &p2);
	planes.push_back (plane);
}

ClippingResult ceClipper::Test (const D3DXVECTOR4& p4, float d) const
{
	D3DXVECTOR3 p (p4.x, p4.y, p4.z);
	FOR_VECTOR(unsigned, i, j, planes)
	{
		const D3DXPLANE& plane = planes[i];
		float v = D3DXPlaneDotCoord (&plane, &p);
		if (v < -d)
		{
			return CR_Out;
		}
	}
	return CR_In;
}

ClippingResult ceClipper::Test (const D3DXVECTOR4& p) const
{
	D3DXVECTOR3 p3 (p.x, p.y, p.z);
	return Test (p3);
}

ClippingResult ceClipper::Test (const D3DXVECTOR3& p) const
{
	FOR_VECTOR(unsigned, i, j, planes)
	{
		const D3DXPLANE& plane = planes[i];
		if (D3DXPlaneDotCoord (&plane, &p) < 0)
		{
			return CR_Out;
		}
	}
	return CR_In;
}



ClippingResult ceClipper::Test (const ceBoundingBox& bbox) const
{
	// just test the 8 points of the bbox
	return Test (bbox.GetPoints(), 8);
}

ClippingResult ceClipper::Test (const D3DXVECTOR3* ps, unsigned num) const
{
	ClippingResult res = CR_In;
	FOR_VECTOR(unsigned, i, j, planes)
	{
		const D3DXPLANE& plane = planes[i];
		bool allIn = true;
		bool allOut = true;
		for (unsigned k=0; k<num; k++)
		{
			float d = D3DXPlaneDotCoord (&plane, &ps[k]);
			if (d >= 0)
			{
				allOut = false;
			}
			if (d < 0)
			{
				allIn = false;
			}
		}
		if (allOut)
		{
			// we have all points outside of one distinct plane.
			// no more tests are needed now.
			return CR_Out;
		}

		// at this point not all of them are out
		// when not all of them are in so we are in between.
		if (!allIn)
		{
			// at least one point is outside.
			res = CR_InOut;
		}
		// wenn cannot return the current result here because the points
		// may be outside of one other distinct plane
	}
	return res;
}


